#include <iostream>
#include <string>
#include <vector>
#include <fstream>

#include <boost/filesystem.hpp>

// 原文档路径
const std::string src_path = "data/input";
// 处理完后文档路径
const std::string raw_path = "data/raw_html/text.txt";


typedef struct DocInfo
{
    std::string title;
    std::string content;
    std::string url;
}DocInfo_t;

bool EnumFiles(const std::string& src_path, std::vector<std::string>& fails_path)
{
    namespace fs = boost::filesystem;
    fs::path root_path(src_path);

    // 判断原文件路径存不存在
    if(fs::exists(root_path) == 0)
        return false;
    
    

    fs::recursive_directory_iterator end;
    fs::recursive_directory_iterator iter(root_path);
    for( ; iter != end; iter++)
    {
        // 判断当前文件的是不是普通文件
        if(fs::is_regular_file(iter->path()) == 0)
            continue;
        // 判断后缀是不是html
        if(iter->path().extension().string() != ".html")
            continue;
        
        fails_path.push_back(iter->path().string());
        // std::cout << fails_path[fails_path.size() - 1] << std::endl;
    }
    //std::cout << "EnumFiles finish" << std::endl;
    return true;
}

bool FileRead(const std::string& path, std::string& text)
{
    std::fstream in(path.c_str(), std::fstream::in);
    if(in.is_open() == 0)
        return false;

    std::string line;
    while(getline(in, line))
    {
        text += line;
    }

    return true;
}

bool PraseTitle(std::string& text, DocInfo_t& doc)
{
    size_t pos1 = text.find("<title>");
    if(pos1 == std::string::npos)
        return false;

    size_t pos2 = text.find("</title>");
    if(pos2 == std::string::npos)
        return false;

    pos1 += 7;
    if(pos1 > pos2)
        return false;
    
    doc.title = text.substr(pos1, pos2 - pos1);

    return true;
}

bool PraseContent(std::string& text, DocInfo_t& doc)
{
    enum status
    {
        LABEL,
        CONTENT
    };

    enum status s = LABEL;
    for(auto c : text)
    {
        if(s == LABEL && c == '>')
        {
            s = CONTENT;
        }
        else if(s == CONTENT)
        {
            if(c == '<') // 内容读完了
            {
                s = LABEL;
                continue;
            }

            if(c == '\n')
                c = ' ';
            doc.content += c;
        }
    }

    return true;
}

bool BuildUrl(std::string& text, const std::string& path, DocInfo_t& doc)
{
    static const std::string head_path = "https://www.boost.org/doc/libs/1_89_0/doc";
    // data/input/html/....
    // url = boost.org/doc/libs/1_89_0/doc/html/....

    size_t pos = path.find("/html");
    if(pos == std::string::npos)
    {
        std::cout << "没有找到html" << std::endl;
        
        return false;
    }

    std::string tail_path = path.substr(pos);    
    doc.url = head_path + tail_path;

    return true;
}

bool PraseHtml(std::vector<std::string>& fails_path, std::vector<DocInfo_t>& fails_result)
{
    for(auto& path : fails_path)
    {
        // 1, 根据路径提取内容
        std::string text;
        if(FileRead(path, text) == 0)
            continue;

        DocInfo_t doc;
        // 2，提取title
        if(PraseTitle(text, doc) == 0)
            continue;
        // std::cout << doc.title << std::endl;

        // 3，提取content
        if(PraseContent(text, doc) == 0)
            continue;

        // 4，制作 url
        if(BuildUrl(text, path, doc) == 0)
            continue;
        //std::cout << doc.url << std::endl;
        

        fails_result.push_back(std::move(doc)); // 完美转发减少拷贝
    }

    return true;
}

bool WriteText(std::vector<DocInfo_t>& fails_result)
{
    std::ofstream out(raw_path, std::ios::out | std::ios::binary);
    if(out.is_open() == 0)
    {
        std::cerr << "open " << raw_path << " error" << std::endl;
        return false;
    }

    std::string text;
    std::string sep = "\3";
    for(auto& doc : fails_result)
    {
        std::string line = doc.title;
        line += sep;
        line += doc.content;
        line += sep;
        line += doc.url;
        line += "\n";
        
        text += line;
    }

    out.write(text.c_str(), text.size());
    
    return true;
}

int main()
{
    // 1, 把所有文档路径处理出来
    std::vector<std::string> fails_path;
    if(EnumFiles(src_path, fails_path) == 0)
    {
        std::cerr << "EnumFiles error" << std::endl;
        return 1;
    }

    // 2, 处理每个路径的文档内容
    std::vector<DocInfo_t> fails_result;
    if(PraseHtml(fails_path, fails_result) == 0)
    {
        std::cerr << "PraseHtml error" << std::endl;
        return 2;
    }
    
    // 3, 把处理好的内容写入文件
    if(WriteText(fails_result) == 0)
    {
        std::cerr << "WriteText error" << std::endl;
        return 3;
    }

    return 0;
}
